#include "CompresorUnario.h"
#include <math.h>
#include <iostream>
#include "string.h"

CompresorUnario::CompresorUnario() {}

// Cuenta cuantos bits estan prendidos en un byte
int CompresorUnario::contador_de_1(unsigned char x) {
	int cant_1;
	for (cant_1 = 0; x != 0; x >>= 1)
		if (x & 1)
			cant_1++;
	return cant_1;
}

// Compresor de números decimales a códigos unarios, dentro del mismo se alloca memoria a unario
void CompresorUnario::comprimir(unsigned int x, unsigned char** unario) {
	unsigned char aux = 0;
	unsigned int resto = x % 8;
	unsigned int cant_bytes = x / 8; // cantidad de bytes a usar para codificar el número
	unsigned int long_cod_unario = x;

	if(long_cod_unario % 8 == 0)
		cant_bytes = long_cod_unario / 8;
	else
		cant_bytes = (long_cod_unario / 8) + 1;

	(*unario) = new unsigned char[cant_bytes];

	unsigned int cond_1 = 1; // Se inicializa en 1 para q el primer byte tenga un 0 adelante
	unsigned int cond_2 = 0; // Se pone en 1 para completar el último byte q no estará lleno
	unsigned int cond_3 = 0; // Si x < 8 entonces entra al primer for solo
	if(resto != 0)
		cond_2 = 1;
	if(x < 8)
		cond_3 = 8 - x + 1;
	//std::cout << "NUMERO UNARIO " << x << std::endl;
	for(unsigned int i = 0; i < cant_bytes; i++)
		(*unario)[i] = 0;
	// Compresor unario
	for (unsigned int i = 1; i <= cant_bytes; i++) {
		if((i == cant_bytes) || ((x < 8))) {
			for (unsigned int j = cond_1; j <= 8 - cond_3; j++) {
				aux = pow(2, j);
				(*unario)[i - 1] |= aux;
			}
		}
		else {
			for (unsigned int j = 0; j < (x - ((i - 1) * 8)); j++) {
				aux = pow(2, j);
				(*unario)[i - 1] = aux | (*unario)[i - 1];
			}
		}
		//std::cout << "Unos del unario: " << this->contador_de_1((*unario)[i - 1]) << std::endl;
		cond_1 = 0;
	}
}

// Descompresor de códigos unarios a números décimales
int CompresorUnario::descompresor(unsigned char *unario) {
	unsigned int numero = 1;
	for(size_t i = 0; i < strlen((char *)unario); i++)
		numero += contador_de_1(unario[i]);
	// std::cout << "Numero descomprimido: " << numero << std::endl;
	return numero;
}

CompresorUnario::~CompresorUnario() {}

